package cn.com.netedge.iot.frontend.biz.redis;

import java.util.List;

import cn.com.netedge.iot.frontend.biz.constants.CallbackConstant;
import cn.com.netedge.iot.frontend.biz.utils.DeviceCmdUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.Message;
import org.springframework.data.redis.connection.MessageListener;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson2.JSON;
import cn.com.netedge.iot.common.constants.CacheKeyConstants;
import cn.com.netedge.iot.common.dataobject.DeviceInfo;
import cn.com.netedge.iot.common.utils.RedisUtil;
import cn.com.netedge.iot.frontend.biz.dao.LogDeviceParamSetupMapper;
import cn.com.netedge.iot.model.log.LogDeviceSetupModel;
import cn.com.netedge.iot.model.notice.ParaConfigNoticeMsgModel;
import cn.com.netedge.iot.model.para.PublicTypeParameter;
import cn.com.netedge.iot.model.task.TaskParaModel;
import cn.com.netedge.iot.model.task.TimeTaskStatusInfoModel;
import cn.com.netedge.iot.protocol.dlms.bll.model.APDUEncode;
import cn.com.netedge.iot.protocol.dlms.entities.CodeObisEntity;
import cn.com.netedge.iot.protocol.dlms.utils.MemoryProcessingUtil;
import cn.com.netedge.iot.protocol.dlms.utils.TaskParaUtil;
import cn.com.netedge.iot.common.utils.StringUtil;

@Component
public class RedisMessageSubscriber implements MessageListener {
    private static Logger logger = LoggerFactory.getLogger(RedisMessageSubscriber.class);


    @Autowired
    private LogDeviceParamSetupMapper logDeviceParamSetupMapper;

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String channel = new String(pattern);
        String body = new String(message.getBody());
        logger.debug("received channel:{} message: {}", channel, body);
        try {
            processMessage(channel, body);
        } catch (Exception e) {
            logger.error("handleTimeTask error: {}", e);
        }
    }

    private void processMessage(String channel, String body) {
        List<DeviceInfo> deviceList;
        switch (channel) {
            case CacheKeyConstants.KEY_DEVICE_TASK_RESULT:
                TaskParaModel taskParaModel = JSON.parseObject(body, TaskParaModel.class);
                if(taskParaModel == null) {
                    logger.debug("task para model is null.");
                    break;
                }
                processCallback(taskParaModel);
            break;
            case CacheKeyConstants.PARA_SETUP_TASK_CHANNEL_NAME:
                ParaConfigNoticeMsgModel configNoticeMsgModel = JSON.parseObject(body, ParaConfigNoticeMsgModel.class);
                if (configNoticeMsgModel == null) {
                    logger.warn("config notice msg model is null");
                    break;
                }
                int planId = configNoticeMsgModel.getParaId();
                deviceList = logDeviceParamSetupMapper.getDeviceInfoListByParaId(planId);
                if (deviceList == null || deviceList.isEmpty()) {
                    logger.warn("plan_id: {} 's log_device_param_setup is empty." ,planId);
                    break;
                }

                logger.info("received para-setup-task, plan-id: {}, para-type: {}", configNoticeMsgModel.getParaId(), configNoticeMsgModel.getConfigType());
                for (DeviceInfo device : deviceList) {
                    startSetupDevice(configNoticeMsgModel, device.getDeviceNumber(), device.getDeviceType());
                }
                break;
            default:
                logger.warn("unknown channel: {}", channel);
                break;
        }
    }

    private void processCallback(TaskParaModel model) {
        switch (model.getCallBackResult()) {
            case CallbackConstant.DEVICE_PARAM_SETUP:
                processDevcieParamSetupCallback(model);
                break;
        
            default:
                break;
        }
    }

    private void processDevcieParamSetupCallback(TaskParaModel model) {
        int setupLogI = (int) model.getTaskStatusInfoModel().getT();
        //更新执行结果
        logDeviceParamSetupMapper.updateSetupResultByLogId(setupLogI, model.getResultCode());
    }

    private void startSetupDevice(ParaConfigNoticeMsgModel configNoticeMsgModel, String deviceNo, int deviceType) {        
        int dt = 0;
        int s = 0;
        //获取方案根据设备号和方案ID获取，参数执行记录
        LogDeviceSetupModel deviceSetupModel = logDeviceParamSetupMapper.getLogDeviceSetupPlanByIdAndDeviceNo(configNoticeMsgModel.getParaId(), deviceNo);
        //获取参数方案
        String schemeJson = deviceSetupModel.getScheme();
        List<PublicTypeParameter> publicTypeParameters = JSON.parseArray(schemeJson, PublicTypeParameter.class);
        //创建参数设置命令
        if (publicTypeParameters == null) return;
        String cmdId = DeviceCmdUtil.genCmdId(deviceNo, deviceType);
        for (PublicTypeParameter publicTypeParameter : publicTypeParameters) {
            TaskParaModel taskParaModel = TaskParaUtil.createTaskParaModel(cmdId, publicTypeParameter.getCode(), "W", false, deviceNo);
            taskParaModel.setParaValue(APDUEncode.getParameter(publicTypeParameter));
            TimeTaskStatusInfoModel<Integer> planId = new TimeTaskStatusInfoModel<>();
            planId.setT(deviceSetupModel.getId());
            taskParaModel.setTaskStatusInfoModel(planId);
            taskParaModel.setCallBackResult(CallbackConstant.DEVICE_PARAM_SETUP);

            //如果阈值设置，需要根据属性2下发的OBIS的数据类型和量纲，进行设置值转换
            if (publicTypeParameter.getCode().equals("71.0.0.17.0.0.255.2")) {
                CodeObisEntity monitorValueCodeObis = MemoryProcessingUtil.getObisByCode(taskParaModel.getParaValue().toString());
                dt = StringUtil.isEmpty(monitorValueCodeObis.getDT()) ? 0 : Integer.parseInt(monitorValueCodeObis.getDT());
                s = StringUtil.isEmpty(monitorValueCodeObis.getS()) ? 0 : Integer.parseInt(monitorValueCodeObis.getS());
            }
            if (publicTypeParameter.getCode().equals("71.0.0.17.0.0.255.4") || publicTypeParameter.getCode().equals("71.0.0.17.0.0.255.5")) {
                taskParaModel.setDataType(dt);
                taskParaModel.setDimension(s);
            }
            //执行抄读命令
            RedisUtil.enqueue(deviceNo, taskParaModel, 13);
            //更新开始时间
            logDeviceParamSetupMapper.updateSetupStartTimeByLogId(deviceSetupModel.getId());
        }
        //回写参数执行状态
    }
}
